/*
 * Copyright (c) 2013.
 * 游戏服务器核心代码编写人陈磊拥有使用权
 * 联系方式：E-mail:13638363871@163.com ;qq:502959937
 * 个人博客主页：http://my.oschina.net/chenleijava
 */

package com.dc.gameserver.serverCore.service.character;


import com.dc.gameserver.baseConfig.Config;
import com.dc.gameserver.exceptions.logicException;
import com.dc.gameserver.extComponents.utilsKit.mybatisPagination.Page;
import com.dc.gameserver.hardCode.ItemOptType;
import com.dc.gameserver.hardCode.PkStatus;
import com.dc.gameserver.hardCode.SessionStatus;
import com.dc.gameserver.proto.gameserverprotoVo.*;
import com.dc.gameserver.serverCore.model.dbsql.modelCache.ModelCacheService;
import com.dc.gameserver.serverCore.model.dbsql.modelService.PlayerService;
import com.dc.gameserver.serverCore.model.dbsql.modelService.RoleItemService;
import com.dc.gameserver.serverCore.model.dbsql.modelVo.TPointPrograss;
import com.dc.gameserver.serverCore.model.dbsql.modelVo.TRole;
import com.dc.gameserver.serverCore.model.dbsql.modelVo.TRoleArea;
import com.dc.gameserver.serverCore.model.gamemodel.*;
import com.dc.gameserver.serverCore.model.gamemodel.script.ScriptFactory;
import com.dc.gameserver.serverCore.service.battle.GameFormula;
import com.dc.gameserver.serverCore.service.cardModule.Card;
import com.dc.gameserver.serverCore.service.cardModule.CardBox;
import com.dc.gameserver.serverCore.service.cardModule.CardBoxManager;
import com.dc.gameserver.serverCore.service.managerService.PlayerManagerService;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import javolution.util.FastTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 游戏对象   </br>
 * player对象不保存数据,所有数据均放在缓存中... ... </br>
 * PK状态中的玩家在预出牌区额牌同步之后，</br>
 * 后端开始计算出牌的结果并将结果返回给客户端   </br>
 */
@Service("player")
@Scope("prototype")
@SuppressWarnings("unchecked")
public class PlayerInstance extends GameCharacter {

   private static final Logger LOGGER= LoggerFactory.getLogger(PlayerInstance.class);

    @Resource
    private PlayerService playerService;

    @Resource
    private RoleItemService roleItemService;

    @Resource
    private ModelCacheService modelCacheService;

    /**玩家帐号编号*/
    private int userID=1;
    /**channel  netty */
    private Channel channel;
    /**角色在线状态*/
    private SessionStatus sessionStatus= SessionStatus.OFFLINE;

    /**player xx 分页信息,每一个player持用一个page对象*/
    private Page page;

    /**对象背包系统载体**/
    private FastTable<ItemCell> itemCells=null;

    /**战斗中的属性，注意 脱离了战斗，将会被销毁***/
    private LevelModel levelModel;//玩家当前进行的关卡实例


    /**玩家上一次领取灵气时间戳**/
    private long achiveTime=0;

    /**
     * 池化背包载体对象
     */
    private static final FastTable<FastTable<ItemCell>> poolItemCellList=new FastTable<FastTable<ItemCell>>();


    /**
     * 构造 函数
     */
    public  PlayerInstance(){
        setOutCardsList(new FastTable<Card>());
        setCardlib(new FastTable<Card>());
        setPkStatus(PkStatus.NO_PK);
        setFirstHand(false);
        setCardType(null);
        setCardBoxID(-1);
        setGiveOut(false);
        setDizzinessTimes(0);
    }


    /**
     * 初始化背包对象池
     */
    public static void IntiItemCellPool(){
          for (int i=0;i!= Config.DEFAULT_VALUE.GAME_VALUE.ItemCellNum;++i){
              poolItemCellList.addLast(createItemCellPanl());
          }
    }


    /**
     * 获取背包对象
     * @return
     */
    public FastTable<ItemCell> nextItemCell(){
        this.itemCells=poolItemCellList.pollFirst();
        if (itemCells==null){
            itemCells=createItemCellPanl();
        }
        return itemCells;
    }


    /**
     * 归还背包对象对象
     */
    private void returnItemCellList(){
        for (ItemCell cell:this.itemCells){
            this.resetItemCell(cell);
        }
        poolItemCellList.addLast(this.itemCells);
    }


    /**
     * {@link com.dc.gameserver.serverCore.service.battle.GameFormula}
     * blood
     * sheild
     * magic
     * attack
     * Defence
     * soual   神识判定
     * recoveryMagic
     * 组装 role 战斗信息
     * 恢复法力值=境界附加的恢复量+装备附加的恢复量+道具增加的恢复量
     *
     */
    public void buildRoleBattleInfo(Monster monster){

        TRole tRole= (TRole) modelCacheService.findByPrefixID(ModelCacheService.ROLE_PREFIX(this.getID()));

//        this.setMaxBlood(tRole.getRolemaxblood()); //最大气血值
//        this.setCurrentBlood(tRole.getRolemaxblood()); //当前气血值

        this.setMaxShield(tRole.getRolemaxshiled()); //最大法力盾
        this.setCurrentShield(tRole.getRolemaxshiled());//当前法力盾


        this.setMaxMagic(tRole.getRolemaxmagic());   //最大法力值    当恢复的时候不能超过这个值；
        this.setCurrentMagic(tRole.getRolemaxmagic()); //当前法力值


        this.setMaxSual(tRole.getRolemaxsual());//最大角色神识值
        this.setSoul(tRole.getRolesual());  //   角色当前神识值


        this.setRecoveryMagic(tRole.getRolerecoverymagic()); //法力恢复速度
        this.setAttack(tRole.getRoleattack()); //对象攻击值
        this.setDefence(tRole.getRoledefence());  //对象防御值
        this.setBaseMaxMomentum(tRole.getRolebasemaxmomentum());//角色基础气势值上限
        this.setBaseMinMomentum(tRole.getRolebaseminmomentum()); //角色基础气势值下限
        this.setSelfFiveType(tRole.getRolefivetype());//角色五行属性    功法决定

        double minCount=(tRole.getRolebaseminmomentum()+tRole.getRoleexperiences()/Math.pow(0xa,tRole.getRolesmalstate()));
        double maxCount=(tRole.getRolebasemaxmomentum()+tRole.getRolemurder()*(0xa-(tRole.getRolemaxstate()-1))/Math.pow(0x64,tRole.getRolemaxstate()));

        setMinCount((int)minCount);
        setMaxCount((int)maxCount);

        StateModel model=ScriptFactory.stateModelFastMap.get(tRole.getStateid()); // 玩家所处的境界
        this.setFangrecoverysheild(model.getFangrecoverysheild()); //法力盾增加
        this.setFangreduceMagic(model.getFangreduceMagic());//法力值减少


        CardNumModel cardNumModel=ScriptFactory.cardNumModelFastMap.get(model.getBigStateID());

        this.setMaxHoldCard(cardNumModel.getMaxHoldCard());
        this.setMaxGetCard(cardNumModel.getMaxGetCard());
        this.setMaxOutCard(cardNumModel.getMaxOutCard());
        //pve  inti monster out cardNum model
        if (monster!=null){
            monster.setMaxHoldCard(cardNumModel.getMaxHoldCard());
            monster.setMaxGetCard(cardNumModel.getMaxGetCard());
            monster.setMaxOutCard(cardNumModel.getMaxOutCard());
        }

        /**战斗变量设置*/
        setPkStatus(PkStatus.NO_PK);
        setFirstHand(false);  //PVE  role 为先手  monster   false
        setCardType(null);
        setCardBoxID(-1);
        setGiveOut(false);
        setDizzinessTimes(0);

    }


    /**
     * 间隔时间 自动回复 soul
     * @param tRole
     */
    public boolean autoRecoverySoul(TRole tRole){
        boolean autoRecovery=false;
        long currentTime  =System.currentTimeMillis();
        Long soultime=tRole.getSoultime();//time2
        int currentSoul=tRole.getRolesual();
        int maxSoul=tRole.getRolemaxsual();
        //超过最大神识，return
        if (currentSoul>=maxSoul){
            return autoRecovery;
        }
        //soul is auto recovery
        autoRecovery=true;
        //神识恢复值
        int recoverySoulValue=ScriptFactory.stateModelFastMap.get(tRole.getStateid()).getRoleSualRecovery();
        long[] recoverySoul= GameFormula.autoRecoverySoul(currentTime,soultime,recoverySoulValue);//获取自动恢复的神识值
       // preTime+t';      t'=Δt*timeInitial
        tRole.setSoultime(soultime+recoverySoul[0]); //矫正时间
        int tempSoul= (int) (recoverySoul[1]+tRole.getRolesual());
        if (tempSoul>=maxSoul){
            tRole.setRolesual(maxSoul);
            sendSoulTime(tRole,0);
        }else {
            tRole.setRolesual(tempSoul);
            sendSoulTime(tRole,currentTime);
        }
        return autoRecovery;
    }


    /**
     * 推送△t 以及当前神识数据
     * @param tRole
     */
    public void sendSoulTime(TRole tRole,long currentTime){
        notifySoulResponse.Builder builder=notifySoulResponse.newBuilder();
        builder.setRoleID(this.getID());
        builder.setSoul(tRole.getRolesual());
        builder.setMaxSoul(tRole.getRolemaxsual());
        if (currentTime!=0){
            Long time=tRole.getSoultime();
            if (time!=null){
                builder.setTime(GameFormula.SoulGoneTime(currentTime,tRole.getSoultime()));//时间
            }
        }
        this.DirectSend(CardBox.wrappedBufferShort(notifySoulResponse.msgID.ID_VALUE,builder.build()));
    }

    /**
     * 根据玩家选中的技能，计算五行技能需求值
     */
    public boolean invokeFiveTypeSkillValue(int skillID){
        boolean status=true;
        try {
            if (skillID==0){
               LOGGER.warn("注意skillID 是 0 ，请检查配置文件！");
            }
            SkillModel skillModel= ScriptFactory.skillModelFastMap.get(skillID);
            this.setSkillfiveType(skillModel.getElement());
            //玩家当前所在关卡
            this.setFiveTypeSkillValue(
                    GameFormula.fiveTypeSkillValue(levelModel,skillModel));


        } catch (logicException e){
            status=false;
            LOGGER.warn("五行技能需求值计算异常，检查逻辑错误！");
        }
        return status;

    }


    /**
     * type: 1,1,1,2,3,4,5,6,7,8 参考资源中的图片描述 人物面板2.png
     * 9(丹药)，10（草药），11（矿石），12（材料），13（其他）
     * 14（灵脉），15（蒲团），16（灵泉）
     * 创建角色面板对象
     * 显示已经装备的对象
     * 面板的部位/类型 以及位置都是确定的
     * 是否有必要将该对象池化？！
     */
    private static FastTable<ItemCell> createItemCellPanl(){

        FastTable<ItemCell> itemCells=new FastTable<ItemCell>();
        //技能  面板
        itemCells.addLast(new ItemCell(0,0,0,1,0,0));
        itemCells.addLast(new ItemCell(0,0,0,1,1,0));
        itemCells.addLast(new ItemCell(0,0,0,1,2,0));

        //神识书
        itemCells.addLast(new ItemCell(0,0,0,2,3,0));

        //功法书  10个位置   对应每一个大境界编号(1~~10)---功法
        itemCells.addLast(new ItemCell(0,0,0,3,4,0));   //练气期
        itemCells.addLast(new ItemCell(0,0,0,3,5,0));   //筑基期
        itemCells.addLast(new ItemCell(0,0,0,3,6,0));   //结丹期
        itemCells.addLast(new ItemCell(0,0,0,3,7,0));   //元婴期
        itemCells.addLast(new ItemCell(0,0,0,3,8,0));   //出窍期
        itemCells.addLast(new ItemCell(0,0,0,3,9,0));   //化神期
        itemCells.addLast(new ItemCell(0,0,0,3,10,0));  //练虛期
        itemCells.addLast(new ItemCell(0,0,0,3,11,0));  //合体期
        itemCells.addLast(new ItemCell(0,0,0,3,12,0));  //大乘期
        itemCells.addLast(new ItemCell(0,0,0,3,13,0));  //渡劫期

        //攻击法宝
        itemCells.addLast(new ItemCell(0,0,0,4,14,0));
        //仙衣
        itemCells.addLast(new ItemCell(0,0,0,5,15,0));
        //配饰
        itemCells.addLast(new ItemCell(0,0,0,6,16,0));
        //挂件
        itemCells.addLast(new ItemCell(0,0,0,7,17,0));
        //神识法宝
        itemCells.addLast(new ItemCell(0,0,0,8,18,0));


        //type: 14（灵脉），15（灵泉），15（灵泉），15（灵泉）,15（灵泉）,16（蒲团）
        //灵脉
        itemCells.addLast(new ItemCell(0,0,0,14,19,0));
        //灵泉
        itemCells.addLast(new ItemCell(0,0,0,15,20,0));
        itemCells.addLast(new ItemCell(0,0,0,15,21,0));
        itemCells.addLast(new ItemCell(0,0,0,15,22,0));
        itemCells.addLast(new ItemCell(0,0,0,15,23,0));
        //蒲团
        itemCells.addLast(new ItemCell(0,0,0,16,24,0));


        //初始化分页操作引用
       // this.page=new Page(0,Config.DEFAULT_VALUE.GAME_VALUE.PrograssPageSize);

        return itemCells;
    }


    /**
     * @return     返回装备的灵泉对象
     */
    public FastTable<ItemCell> getSpriteItem(){
        FastTable<ItemCell> spriteList=new FastTable<ItemCell>();
        for (int index= 0x14;index!= 0x18;++index){ //20~~24
            ItemCell cell=this.itemCells.get(index);
            if (cell.getItemID()!=0&&cell.getType()== 0xf&&cell.getItemType()!= 0x0){
                spriteList.addLast(cell);
            }
        }
        return spriteList;
    }



    /**
     * 获取指定位置的item cell对象
     * @param itemLocation 位置  0---24
     * @return     cell对象
     */
    public ItemCell getCellByLocation(int itemLocation){
        if (itemLocation<0||itemLocation> 0x18){
            throw new  logicException("itemLocation 应该在区间[0,24]，检查逻辑！");
        }
        return this.itemCells.get(itemLocation);
    }


    /**
     * 获取位置4~~13位置上的功法，且是已经装备上
     * @return  获取已经开启的功法
     */
    public FastTable<ItemCell> getGongItem(){
        FastTable<ItemCell> GongList=new FastTable<ItemCell>();
        for (int index= 0x4;index!=0xe;++index){
            ItemCell cell=this.itemCells.get(index);
            if (cell.getItemID()!=0){
                GongList.addLast(cell);
            }
        }
        return GongList;
    }

    /**
     * 根据境界 返回相应开启的功法
     * @param stateID  当前角色所持有的大境界编号
     * @return   FastTable<Integer>   已经开启的大境界编号 ---对应大境界编号
     */
    public  FastTable<Integer> OpenGongByStateID(int stateID){
        FastTable<Integer> stateIDList=new FastTable<Integer>();
        int limit=stateID+ 0x1;
        for (int id= 0x1;id!=limit;++id){
            stateIDList.addLast(id);
        }
        return stateIDList;
    }

    /**
     * 检查当前的items是否已经装备到其他的cell上面，如果存在，那么就直接返回
     * @param itemID     道具和装备的编号可能会存在相同，因此准确查找加上类型
     * @return
     */
    public ItemCell checkItemCellByItemID(int itemID,int itemType){
         for (ItemCell cell:this.itemCells){
             if (cell.getItemID()==itemID&&cell.getItemType()==itemType){
                 return cell;
             }
         }
          return null;
    }



    /**
     * 获取部位/类型值
     * @param itemLocation 位置
     * @return   部位/类型
     */
    public int getTypeByLocation(int itemLocation){
        return this.itemCells.get(itemLocation).getType();
    }


    /**
     *
     *   20 21 22 23
     * @return    返回开启的灵泉位置编号
     */
    public  FastTable<Integer> openSpriteLocation(int SpriteID){
         if (SpriteID< 0x14 ||SpriteID> 0x17){
            return null;
        }
        int tempSpriteID=SpriteID+ 0x1;
        FastTable<Integer> tempListID=new FastTable<Integer>();
        for (int i= 0x14;i!=tempSpriteID;++i){
            tempListID.addLast(i);
        }
        return tempListID;
    }

    /**
     * 检查该技能是否被装备
     * @param skillID
     * @return
     */
    public boolean checkSkill(int skillID){
       boolean haveSkill=false;
       for (int i=0;i!= 0x3;++i){
           ItemCell cell=this.itemCells.get(i);
           if (cell.getItemTypeID()==skillID){
               haveSkill=true;
               return haveSkill;
           }
       }
      return haveSkill;
    }


    /**
     * 根据部位/类型 返回大类型（1：技能 2.秘籍 3.装备）
     * @param type    1（技能1）,1（技能2）,1（技能3）,2（神识书）,3（功法书）,4（攻击法宝）
     *                   ,5（仙衣）,6（配饰）,7（挂件）,8（神识法宝） 参考资源中的图片描述 人物面板2.png
     * @return     1：技能 2.秘籍 3.装备
     */
    public int getTypeByType(int type){
        if (type== 0x1){
            return 0x1;
        }else if (type>= 0x4 &&type<= 0x8){
            return 0x3;
        }else {
            return 0x2;
        }
    }

    /**
     * 重置cell对象
     * @param cell
     */
    public void resetItemCell(ItemCell cell){
        cell.setItemID(0x0);     //编号
        cell.setItemTypeID(0x0); //配置编号
        cell.setItemType(0x0); //对象类型 1.装备 2.秘籍 3.道具
        cell.setStateID(0x0);
    }


    /**
     * 检查出牌是否合法  ---来自牌库系统发的
     * @param outCardList
     * @return
     */
    public boolean checkCard(List<netCardVO> outCardList){
        boolean status=true;
        FastTable<String> TYPE_LIST= new FastTable<String>();
        FastTable<String> count_LIST= new FastTable<String>();
        for (com.dc.gameserver.serverCore.service.cardModule.Card card:getCardlib()){
            TYPE_LIST.add(card.getType()+"");
            count_LIST.add(card.getCount()+"");
        }
        for (netCardVO cardVO:outCardList){
            int cardType=cardVO.getCardNum();
            int cardCount=cardVO.getCardCount();
            if (!count_LIST.contains(cardCount+"")&&!TYPE_LIST.contains(cardType+"")){
                status=false;
                return status;
            }
        }
        return status;
    }


    /**
     *更新神识关卡
     * @param soullevelModel
     */
    public void updateSoulLevel(LevelModel soullevelModel,boolean battleStatus,int roundTimes){
        int roleID=this.getID();
        int nowLevelID=soullevelModel.getId();
        String levelRegion=ModelCacheService.POINT_PROGRASS_PREFIX(roleID);
        List<TPointPrograss> pointPrograssList=
                (List<TPointPrograss>) modelCacheService.findListByPrefixID(levelRegion);
        TPointPrograss havePrograss=null;
        for (TPointPrograss prograss:pointPrograssList){
            if (prograss.getPointid()==nowLevelID){
                havePrograss=prograss;
                pointPrograssList.remove(prograss);
                break;
            }
        }
        levelOverResponse.Builder levelOverbuilder=levelOverResponse.newBuilder();
        //判定关卡星级数
        byte starts=GameFormula.stars(this.getCurrentShield(),this.getMaxShield(),roundTimes);
        levelOverbuilder.setRoundTimes(roundTimes);  //回合数
        levelOverbuilder.setStarts(starts); //星级数量
        levelOverbuilder.setBattleStatus(battleStatus); // true :闯关成功 false:闯关失败

        if (havePrograss!=null){
            havePrograss.setPointstarnum(starts);
            boolean firstStartThree=false;
            int tempStars=havePrograss.getPointstarnum();   //当前的星级数量
            if (starts>tempStars){
                if (tempStars!= 0x3&&starts== 0x3){   //不是全三星 ，那么判定是否是全三星
                    firstStartThree=true; // 是否首次对次关卡获取三星
                    havePrograss.setFirststartrward(firstStartThree);
                    levelOverbuilder.setFirstStartThree(firstStartThree);  // 是否首次对次关卡获取三星
                }
                havePrograss.setPointstarnum(starts);
            }
            //每日通关次数
            int tempTimes= havePrograss.getPointpercompletenum() + 0x1;
            int completeMaxPerDay= levelModel.getCompleteMaxPerDay();
            if (tempTimes>completeMaxPerDay){
                notifyLevelPercompletenumResponse.Builder _builder=notifyLevelPercompletenumResponse.newBuilder();
                _builder.setLevelID(nowLevelID);
                _builder.setPercompletenum(completeMaxPerDay);
                this.DirectSend(CardBox.wrappedBufferShort(notifyLevelPercompletenumResponse.msgID.ID_VALUE,_builder.build()));
                tempTimes=completeMaxPerDay;//最大次数，超过限制，需要通过购买来重置
            }
            havePrograss.setPointpercompletenum(tempTimes);//每天完成关卡的次，每天会清0,如果tempTimes> completeMaxPerDay,那么将会通知前端购买获取更多的可玩关卡次数

            //区域关卡通关次数
            Integer completenum= havePrograss.getCompletenum();
            if (completenum!=null) {
                havePrograss.setCompletenum(completenum+0x1); //关卡完成的总次数
            }else {
                havePrograss.setCompletenum(0x1); //关卡完成的总次数
            }
            playerService.updateLevel(havePrograss);
            pointPrograssList.add(havePrograss);
            modelCacheService.addListByPrefixID(levelRegion,pointPrograssList);
        }else {
            //new soul
            TPointPrograss newSoulLevel=new TPointPrograss();
            newSoulLevel.setPointid(levelModel.getId());       //关卡编号
            newSoulLevel.setPointstarnum(starts);//关卡星级数量
            newSoulLevel.setPointstatus((byte) 0x0);     //关卡完成状态 1:未完成;2.已完成;
            newSoulLevel.setBelongareaid(levelModel.getAreaID()); //关卡所属区域ID
            newSoulLevel.setRoleid(roleID); //角色ID
            newSoulLevel.setPointtype(levelModel.getLevelType());  //关卡类型 1.普通 2.神识 3.隐藏
            newSoulLevel.setPointpercompletenum(0x1); //每天完成的次数
            newSoulLevel.setCompletenum(0x1);
            newSoulLevel.setPointlasttimes(0);   //关卡剩余可完成（可玩+）次数  针对隐藏关卡
            playerService.insertSoulLevel(newSoulLevel);
            pointPrograssList.add(newSoulLevel);
            modelCacheService.addListByPrefixID(levelRegion,pointPrograssList);
        }
        CardBox cardBox=CardBoxManager.getCardBoxByID(this.getCardBoxID());
        cardBox.submitMessageToEveryOne(CardBox.wrappedBufferShort(levelOverResponse.msgID.ID_VALUE, levelOverbuilder.build()));
    }
    /**
     *玩家的神识上限满足关卡需求，开启对应的神识关卡
     *
     * @param lastLevelID     最后一个关卡编号
     * @param levelModel      当前关卡
     * @param areaID          当前区域ID
     */
    public void updateLevelAndArea(int lastLevelID,LevelModel levelModel,int areaID,boolean battleStatus,int roundTimes){
        int  nowLevelID=levelModel.getId();
        int roleID=this.getID();
        levelOverResponse.Builder levelOverbuilder=levelOverResponse.newBuilder();
        //判定关卡星级数
        byte starts=GameFormula.stars(this.getCurrentShield(),this.getMaxShield(),roundTimes);
        //找出当前对应的关卡
        List<TPointPrograss> pointPrograssList=
                (List<TPointPrograss>) modelCacheService.findListByPrefixID(ModelCacheService.POINT_PROGRASS_PREFIX(roleID));
        TPointPrograss prograss=null;
        for (TPointPrograss tPointPrograss:pointPrograssList){
            if (tPointPrograss.getPointid()==nowLevelID){
                prograss=tPointPrograss;
                pointPrograssList.remove(tPointPrograss);
                break;
            }
        }
       if (prograss!=null){
            boolean firstStartThree=false;
            int tempStars=prograss.getPointstarnum();   //当前的星级数量
            if (starts>tempStars){
                if (tempStars!= 0x3&&starts== 0x3){   //不是全三星 ，那么判定是否是全三星
                    firstStartThree=true; // 是否首次对次关卡获取三星
                    prograss.setFirststartrward(firstStartThree);
                    levelOverbuilder.setFirstStartThree(firstStartThree);  // 是否首次对次关卡获取三星
                }
                prograss.setPointstarnum(starts);
            }
            prograss.setPointstatus((byte) 0x2);//标记关卡完成
            int tempTimes= prograss.getPointpercompletenum() + 0x1;
            int completeMaxPerDay= levelModel.getCompleteMaxPerDay();
            if (tempTimes>completeMaxPerDay){
                notifyLevelPercompletenumResponse.Builder _builder=notifyLevelPercompletenumResponse.newBuilder();
                _builder.setLevelID(nowLevelID);
                _builder.setPercompletenum(completeMaxPerDay);
                this.DirectSend(CardBox.wrappedBufferShort(notifyLevelPercompletenumResponse.msgID.ID_VALUE,_builder.build()));
                tempTimes=completeMaxPerDay;//最大次数，超过限制，需要通过购买来重置
            }
            prograss.setPointpercompletenum(tempTimes);//每天完成关卡的次，每天会清0,如果tempTimes> completeMaxPerDay,那么将会通知前端购买获取更多的可玩关卡次数
            Integer completenum= prograss.getCompletenum();
            if (completenum!=null) {
                prograss.setCompletenum(completenum+0x1); //关卡完成的总次数
            }else {
                prograss.setCompletenum(0x1); //关卡完成的总次数
            }


             //update db  and cache
            this.updateLevel(prograss);
            pointPrograssList.add(prograss);
            modelCacheService.addListByPrefixID(ModelCacheService.POINT_PROGRASS_PREFIX(roleID),pointPrograssList);
            levelOverbuilder.setRoundTimes(roundTimes);
            levelOverbuilder.setStarts(starts); //星级数量
            levelOverbuilder.setBattleStatus(battleStatus); // true :闯关成功 false:闯关失败
            CardBox cardBox=CardBoxManager.getCardBoxByID(this.getCardBoxID());
            cardBox.submitMessageToEveryOne(CardBox.wrappedBufferShort(levelOverResponse.msgID.ID_VALUE, levelOverbuilder.build()));
        }
        //更新当前关卡,area信息 ，更新db,缓存
        //返回当前区域对应的关卡列表
        //update area db ，complete Num ++1
        List<TRoleArea> tRoleAreaList=
                (List<TRoleArea>) modelCacheService.
                        findListByPrefixID(ModelCacheService.AREA_PREFIX(roleID));
        TRoleArea tRoleArea=null;
        //找出当前区域的db对象
        for (TRoleArea roleArea:tRoleAreaList){
            if (roleArea.getRoleareaid()==areaID){
                tRoleArea=roleArea;
                tRoleAreaList.remove(roleArea);//remove area
                break;
            }
        }
        if (tRoleArea!=null){
            // 检查关卡是否全三星
            boolean allStart=true;//全三星
            int levelModeNum=ScriptFactory.mainLevelFastMap.get(areaID).size();
            List<TPointPrograss> pointPrograsses=
                    (List<TPointPrograss>) modelCacheService.findListByPrefixID(ModelCacheService.POINT_PROGRASS_PREFIX(roleID));
            FastTable<TPointPrograss> pointPrograssFastTable=new FastTable<TPointPrograss>();
            for (TPointPrograss p:pointPrograsses){
                if (p.getBelongareaid()==areaID){
                    pointPrograssFastTable.addLast(p);
                }
            }
            //not over level
            if (pointPrograssFastTable.size()!=levelModeNum){
                 allStart=false;
            }
            if (allStart){
                for (TPointPrograss pointPrograss:pointPrograssFastTable){
                    if (pointPrograss.getPointstarnum()!= 0x3){
                        allStart=false;//not all start
                        break;
                    }
                }
            }
            pointPrograssFastTable.clear();
            pointPrograssFastTable=null;
            if (allStart){
                //更新当前区域全三星奖励字段
                //1.未领取(已经达到三星)，2.已领取，3.未达三星
                tRoleArea.setAllstartsreword((byte)0x1);
                //区域关卡闯关全三星奖励
                allStatrsResponse.Builder builder=allStatrsResponse.newBuilder();
                builder.setAllStatrsReword((byte)0x1);
                builder.setAreaID(areaID);
                this.DirectSend(CardBox.wrappedBufferShort(allStatrsResponse.msgID.ID_VALUE,builder.build()));
            }
            this.playerService.updateArea(tRoleArea);
            tRoleAreaList.add(tRoleArea);
            modelCacheService.addListByPrefixID(ModelCacheService.AREA_PREFIX(roleID),tRoleAreaList);
        }

        if (nowLevelID==lastLevelID){
            // 刷入area区域，刷入area区域的第一个关卡； nextAreaID=areaID+1
            int nextAreaID=areaID+1;
            AreaModel areaModel=ScriptFactory.areaModelFastMap.get(nextAreaID);
            int ID=areaModel.getId();
            if (ID!=nextAreaID){
                throw new logicException("区域编号不连续，检查配置文件... ...");
            }
            FastTable<LevelModel> levelModels=ScriptFactory.mainLevelFastMap.get(ID);
            LevelModel model=null;
            for (LevelModel level:levelModels){
                if (level.getAreaID()==ID){
                    model=level;
                    break;
                }
            }
            if (model!=null&&areaModel!=null){
                //检查是否已经刷入了当前关卡
                List<TRoleArea> roleAreas=
                        (List<TRoleArea>) modelCacheService.
                                findListByPrefixID(ModelCacheService.AREA_PREFIX(roleID));

                boolean haveArea=false,havaLevel=false;
                for (TRoleArea roleArea:roleAreas){
                    if (roleArea.getRoleareaid().equals(areaModel.getId())){
                        haveArea=true;
                        break;
                    }
                }
                List<TPointPrograss> prograsses=
                        (List<TPointPrograss>) modelCacheService.findListByPrefixID(ModelCacheService.POINT_PROGRASS_PREFIX(roleID));
                for (TPointPrograss level:prograsses){
                     if (level.getPointid().equals(model.getId())){
                         havaLevel=true;
                         break;
                     }
                }

                if (!haveArea&&!havaLevel){
                    this.playerService.openNewAreaAndLevel(roleID,areaModel,model);
                    //notify levelModel  and areaModel information
                    openAreaResponse.Builder _areaBuilder=openAreaResponse.newBuilder();
                    _areaBuilder.setAreaID(ID) ;
                    this.DirectSend(CardBox.wrappedBufferShort(openAreaResponse.msgID.ID_VALUE,_areaBuilder.build()));
                    openLevelResponse.Builder _levelBuilder=openLevelResponse.newBuilder();
                    _levelBuilder.setLevelID(model.getId());
                    this.DirectSend(CardBox
                            .wrappedBufferShort(openLevelResponse.msgID.ID_VALUE,_levelBuilder.build()));
                }
            }
        }else {
            //刷入下一个关卡   ,++1 completeNum
            FastTable<LevelModel> levelModels =ScriptFactory.mainLevelFastMap.get(areaID);
            LevelModel model=null;   // next levelID
            int nexLevelID=nowLevelID+1;  //区域对应的关卡列表编号连续
            for (LevelModel level:levelModels){
                if (level.getId()==nexLevelID){
                    model=level;
                    break;
                }
            }

            //检查是否包含该关卡
            boolean haveLevel=false;
            List<TPointPrograss> prograsses=
                    (List<TPointPrograss>) modelCacheService.findListByPrefixID(ModelCacheService.POINT_PROGRASS_PREFIX(roleID));
            for (TPointPrograss level:prograsses){
                if (level.getPointid().equals(model.getId())){
                    haveLevel=true;
                    break;
                }
            }

            if (model!=null&&!haveLevel){
                this.playerService.openLevel(roleID,model);
                openLevelResponse.Builder _levelBuilder=openLevelResponse.newBuilder();
                _levelBuilder.setLevelID(model.getId());  //开启新的关卡编号
                this.DirectSend(CardBox
                        .wrappedBufferShort(openLevelResponse.msgID.ID_VALUE, _levelBuilder.build()));
            }
        }
    }

    /**
     * 更新关卡
     * @param prograss
     */
    public void  updateLevel(TPointPrograss prograss){
        this.playerService.updateLevel(prograss);
    }

    /**
     *玩家获取系统产生的物品接口
     * int[0]:关卡编号；int[1]：掉落的物品类型编号;int[2]:掉落物品数量；int[3]：物品类型；
     *
     */
    public void insterItemToPlayer(int[] items){
        this.roleItemService.recordGoods(this, items, ItemOptType.LEVEL_REWORD.getValue());
    }

    /**
     * 发送数据
     */
    @Override
    public final void DirectSend(final ByteBuf buffer) {
        this.channel.writeAndFlush(buffer) ;
    }
    /**
     * 移除 玩家牌库中的牌
     * @param cardType
     * @param count
     *
     * 返回被移除的card,注意该对象将会被回收
     */
    public Card removeIncardlib(int cardType,int count){
        FastTable<Card> cards   =getCardlib();
        for (com.dc.gameserver.serverCore.service.cardModule.Card card:cards){
            if (card.getType()==cardType&&card.getCount()==count){
                cards.remove(card);
                return card;
            }
        }
        return null;
    }

    /**
     *回合开始
     * 添加系统分发的纸牌对象列表
     * @param disCardList   系统分发的纸牌对象列表
     */
    public void add(Card[] disCardList){
        FastTable<Card> cards=getCardlib();
        cards.addAll(disCardList);
        cards.sort();    //快速排序
    }

    /**
     * 添加出牌对象到预出牌区列表对象 outCardsList
     * @param card
     */
    @Override
    public void addOutCard(Card card){
        this.getOutCardsList().addLast(card);
    }
    /**
     * 回合结束（注意没有离开PK状态且PK没有结束）
       当前回合结束，清除当前回合中的资源，重置，准备下一次回合资源
     */
    @Override
    public void clearRoundResource() {
        if (!this.getOutCardsList().isEmpty()){
           this.recoverRoundCard();   //回收
        }
        this.setGiveOut(false);
    }

    /**
     * 离开PK状态
     * 清除资源 ,除非下线 下线状态  card  cardBox 都将被回收
     */
    @Override
    public void clearAllResourceOutOfPK(CardBox cardBox) {
        RecoverCard(cardBox);
        this.setCardBoxID(-1);
        this.setFirstHand(false);
        this.setActionOutCard(false);
        this.setGiveOut(false);

        this.setPkStatus(PkStatus.NO_PK);
        this.setDizzinessTimes(0);//眩晕 set  0
        this.setLevelModel(null);
        this.setMaxHoldCard(0);
    }


    /**
      PK结束，清理PK资源,
     */
    @Override
    public void clearPkResourceWithRoundOver(CardBox cardBox){
        RecoverCard(cardBox);
        this.setCardBoxID(-1);
        this.setFirstHand(false);
        this.setActionOutCard(false);
        this.setGiveOut(false);

        this.setPkStatus(PkStatus.NO_PK);
        this.setDizzinessTimes(0);//眩晕 set  0
        this.getOutCardsList().clear();
        this.setLevelModel(null);
        this.setMaxHoldCard(0);
    }


    /**
     * offline
     */
    private void destoryPlayer(){
        this.page=null;
        this.setOutCardsList(null);
        this.setCardlib(null);
        setPkStatus(null);
        setCardType(null);
        setFirstHand(false);
        this.sessionStatus=SessionStatus.OFFLINE;
        this.setDizzinessTimes(0);
        setActionOutCard(false);
        setCardBoxID(-1);
        PlayerManagerService.INTEGER_PLAYER_INSTANCE_MAP.remove(this.getID());
        returnItemCellList();
    }



    /**
     * 持久化玩家的数据</br>
     * 释放系统资源   </br>
     * #+逻辑分发处理线程+#
     */
    @Override
    public void saveAndDestory(){
        try {
            int roleID=this.getID();
            if (roleID!=0){
                /***save db and clear cache */
                playerService.saveDbAndClearCache(roleID);
            }
            if (this.getPkStatus()==PkStatus.YES_PK){
                CardBoxManager.clearCardBoxAndCardIfPlayerOffile(this.getCardBoxID());
                notifyOfflineResponse.Builder  builder=notifyOfflineResponse.newBuilder();
                builder.setPlayerID(this.getID());
                this.DirectSend(CardBox.wrappedBufferShort(notifyOfflineResponse.msgID.ID_VALUE, builder.build()));
            }
            //销毁玩家对象资源
            destoryPlayer();
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public long getAchiveTime() {
        return achiveTime;
    }

    public void setAchiveTime(long achiveTime) {
        this.achiveTime = achiveTime;
    }
    public LevelModel getLevelModel() {
        return levelModel;
    }

    public void setLevelModel(LevelModel levelModel) {
        this.levelModel = levelModel;
    }

    public FastTable<ItemCell> getItemCells() {
        return itemCells;
    }

    public void setItemCells(FastTable<ItemCell> itemCells) {
        this.itemCells = itemCells;
    }

    public SessionStatus getSessionStatus() {
        return sessionStatus;
    }

    public void setSessionStatus(SessionStatus sessionStatus) {
        this.sessionStatus = sessionStatus;
    }

    public Channel getChannel() {
        return channel;
    } 
    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public int getUserID() {
        return userID;
    }

    public void setUserID(int userID) {
        this.userID = userID;
    }

    public Page getPage() {
        return page;
    }


}
